﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Diagnostics;
using System.Windows;

namespace SkeletalAnimation3D.Core
{
    class Animator : DependencyObject
    {
        private Stopwatch _stopwatch = new Stopwatch();
        private bool _isPlayingAnimation;
        private BoneAnimation _animation;
        private int _loops = 1;
        private double _speed = 1;
        private bool _autoReverse = false;
        private IInterpolate _interpolator;

        public Animator()
        {

        }

        public Animator(IInterpolate interpolator)
        {
            _interpolator = interpolator;
        }

        public bool IsPlayingAnimation
        {
            get
            {
                return _isPlayingAnimation;
            }
        }

        public void Play(BoneAnimation animation, int loops, double speed, bool autoReverse)
        {
            _animation = animation;
            _loops = loops;
            _speed = speed;
            _autoReverse = autoReverse;
            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
            _stopwatch.Reset();
            _stopwatch.Start();
            _isPlayingAnimation = true;
        }

        protected virtual void Interpolate(double progress)
        {
            _interpolator.Interpolate(progress);
        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            bool endAnimation = false;
            double elapsedMilliseconds = _stopwatch.ElapsedMilliseconds * _speed;
            double maxMilliseconds = _animation.Duration.TimeSpan.TotalMilliseconds * (_autoReverse ? 2 : 1) * _loops;
            if (_loops == -1 || elapsedMilliseconds < maxMilliseconds)
            {
                int repetitions = Convert.ToInt32(Math.Truncate(elapsedMilliseconds / _animation.Duration.TimeSpan.TotalMilliseconds));
                int maxRepetitions = _loops * (_autoReverse ? 2 : 1);
                if (_loops == -1 || repetitions < maxRepetitions)
                {
                    double relativeProgress = (elapsedMilliseconds - (repetitions * _animation.Duration.TimeSpan.TotalMilliseconds)) / _animation.Duration.TimeSpan.TotalMilliseconds;
                    if (_autoReverse && repetitions % 2 == 1)
                    {
                        relativeProgress = 1.0 - relativeProgress;
                    }
                    Interpolate(relativeProgress);
                }
                else
                {
                    endAnimation = true;
                }
            }
            else
            {
                endAnimation = true;
            }
            if (endAnimation)
            {
                StopPlaying();
            }
        }
        
        internal void PausePlaying()
        {
            if (_isPlayingAnimation)
            {
                _stopwatch.Stop();
                CompositionTarget.Rendering -= new EventHandler(CompositionTarget_Rendering);
            }
        }

        internal void ContinuePlaying()
        {
            if (_isPlayingAnimation && !_stopwatch.IsRunning)
            {
                CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
                _stopwatch.Start();
            }
        }

        internal void StopPlaying()
        {
            if (_isPlayingAnimation)
            {
                _stopwatch.Stop();
                CompositionTarget.Rendering -= new EventHandler(CompositionTarget_Rendering);
                _isPlayingAnimation = false;
            }
        }

        internal void ShowAnimationStill(BoneAnimation animation, double offset)
        {
            _interpolator.ShowAnimationStill(animation, offset);
        }


        internal void ShowAnimationFrame(BoneAnimation animation, int frame)
        {
            _interpolator.ShowAnimationFrame(animation, frame);
        }

        internal void ShowMesh()
        {
            _interpolator.ShowMesh();
        }







       
    }
}
